/*
 *  NFCSigning - Open source library for signing/validation of NDEF messages
 *  Copyright (C) 2009-2010 The NFCSigning Team
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 *
 */
package org.nfcsigning.algorithm;

import java.io.IOException;
import java.math.BigInteger;
import org.bouncycastle.asn1.DERObjectIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.util.encoders.Hex;

/**
 *
 * @author Markus Kilås
 */
public class ECDSAVerifier implements SignatureVerifier {

    public static final DERObjectIdentifier ECDSA = new DERObjectIdentifier("1.2.840.10045.2.1");
    public static final DERObjectIdentifier SHA1withECDSA = new DERObjectIdentifier("1.2.840.10045.4.1");
    private static ECDSAVerifier instance;

    public static ECDSAVerifier getInstance() {
        if (instance == null) {
            instance = new ECDSAVerifier();
        }
        return instance;
    }

    // TODO: change Certificate to PublicKey
    public boolean verifySignature(byte[] signature, byte[] coveredBytes, PublicKey key) throws SignatureException {

        try {
            SubjectPublicKeyInfo pkInfo = key.getSubjectPublicKeyInfo();

            // Signature
//            System.out.println("Verify: " + Utils.toFixedHexString(signature));
            BigInteger[] rs = ECDSASigner.decodeAsInX962(signature);
            BigInteger r = rs[0];
            BigInteger s = rs[1];

            // Domain model variables
            BigInteger q = new BigInteger("6277101735386680763835789423207666416083908700390324961279");
            BigInteger a = new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16);
            BigInteger b = new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16);
            BigInteger n = new BigInteger("6277101735386680763835789423176059013767194773182842284081");
            byte[] G = Hex.decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012");

            // Public key
            byte[] Q = pkInfo.getPublicKeyData().getBytes();

            // Domain model
            ECCurve.Fp curve = new ECCurve.Fp(q, a, b);
            ECDomainParameters ECDomPara = new ECDomainParameters(
                    curve, curve.decodePoint(G), n);
            ECPublicKeyParameters pubKey = new ECPublicKeyParameters(
                    curve.decodePoint(Q), ECDomPara);

            // BouncyCastle signer
            org.bouncycastle.crypto.signers.ECDSASigner signer = new org.bouncycastle.crypto.signers.ECDSASigner();
            signer.init(false, pubKey);

            Digest digest = DigestFactory.getDigest("SHA-1");
            digest.update(coveredBytes, 0, coveredBytes.length);

            byte[] digestBytes = new byte[digest.getDigestSize()];
            digest.doFinal(digestBytes, 0);
//            System.out.println("Digest: " + Utils.toFixedHexString(digestBytes));

            return signer.verifySignature(digestBytes, r, s);
        } catch (IOException ex) {
            ex.printStackTrace();
            throw new RuntimeException("IOException: " + ex.getMessage());
        }
    }
}
